package com.jt.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import com.jt.vo.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @author 刘昱江
 * 时间 2021/5/11
 */
@Service
//@Transactional  //当前类中的所有的方法都有事务控制 增/删/改需要事务  查询不要事务.
public class UserServiceImpl implements UserService{

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> findAll() {
        return userMapper.selectList(null);
    }

    /**
     * 需求:
     *      1.根据用户名和密码查询数据库
     *      2.将密码进行加密处理 md5加密方式
     *      3.如果用户名和密码正确 返回token
     *      4 UUID: 每次生成的UUID几乎不重复.   重复概率 2^128/1
     *        b809cd3e-f4fa-11eb-b396-52152e05da50
     * @param user  作用: 在未来生成API文档时 有效果 一般都是默认的
     * @return
     */
    @Override
    public String login(User user) {
        //1.将密码进行加密的处理
        String password = user.getPassword(); //明文
        //2. 将字符串 转化为字节数组
        byte[] passByte = password.getBytes();
        //   将明文加密
        String md5Pass = DigestUtils.md5DigestAsHex(passByte);
        //3. 根据用户名和密文查询数据库
        //Sql: select * from user where uname="xxx" and ps="xx"
        //根据对象中不为null的属性充当where条件!!!!
        user.setPassword(md5Pass);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
        //用户名和密码是否与数据库中的匹配!!!!!
        //BUG: 根据MD5加密 admin123456 可能由于windows版本问题 可能出现偏差
        //  admin123456 A  !=  B  将数据库中的密码改为B
        //从数据库中获取结果
        User userDB = userMapper.selectOne(queryWrapper);

        //不能理解!! 面向对象的知识 理解不到位!!!
        if(userDB == null){ //用户名和密码错误 返回null
            return null;    //业务流程结束
        }

        //如果程序执行到这一行,则数据用户的输入正确的. 返回token
        String token = UUID.randomUUID().toString()
                        .replace("-","");
        return token;
    }

    /**
     * 以MP的方式分页查询
     * 需求:
     *  1.分页查询 List<user>
     *  2.获取记录总数   封装pageResult对象
     *
     * @param pageResult
     * @return
     */
    @Override
    public PageResult getUserList(PageResult pageResult) {
        //第一部分 实现数据的封装!!!
        int pageNum = pageResult.getPageNum();  //获取页面
        int pageSize = pageResult.getPageSize();//获取条件
        //参数1: page分页对象
        Page<User> page = new Page(pageNum,pageSize);
        //参数2: 分页的查询条件  username模糊查询
        //问题:  如果用户没有传递query  like关键字  拼接参数
        //动态拼接: 传参拼接like  condition:true 拼接like条件
        //         false 不拼接 like关键字
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //判断用户是否传参  如果传参 返回true   反之 返回false
        boolean flag = StringUtils.hasLength(pageResult.getQuery());
        queryWrapper.like(flag,"username",pageResult.getQuery());

        //规则: page2个参数 根据分页查询返回 total/分页后的记录 4个参数
        page = userMapper.selectPage(page,queryWrapper);
        //根据分页对象获取记录
        List<User> userList = page.getRecords();
        //根据分页对象获取总数
        long total = page.getTotal();
        //封装VO对象 返回数据
        pageResult.setTotal(total).setRows(userList);
        return pageResult;
    }

    //user对象的有效数据  id=xxx  status=true/false
    @Override
    @Transactional
    public void updateStatus(User user) {
        //根据其中不为null的元素当作set条件   id当作唯一的where条件
        userMapper.updateById(user);
    }

    /**
     *  新增入库:
     *      1.密码需要加密处理
     *      2.应该赋值默认状态 true
     *      3.需要添加时间  创建/修改 (周日优化)
     */

    @Override
    @Transactional
    public void addUser(User user) {
        //1.密码加密
        byte[] bytes = user.getPassword().getBytes();
        String md5Pass = DigestUtils.md5DigestAsHex(bytes);
        user.setPassword(md5Pass);
        //2.添加默认状态
        user.setStatus(true);
        //3.添加时间  目的保证时间统一
        //Date date = new Date();
        //user.setCreated(date).setUpdated(date);

        //4.实现入库
        userMapper.insert(user);
    }

    @Override
    public User getUserById(Integer id) {

        return userMapper.selectById(id);
    }

    //参数: id主键  电话/邮箱
    //语法: 根据对象中不为null的属性当作set条件 id当作唯一where条件
    @Override
    @Transactional
    public void updateUser(User user) {

        userMapper.updateById(user);
    }

    /**
     * 关于Spring中的事务策略说明
     *  0.Spring内部有事务的管理器,默认开启.
     *  1.Spring只负责拦截运行时异常.
     *    异常类型:  1.运行时异常  2.检查异常/编译异常 由程序员自己控制
     *  2.属性1: rollbackFor 可以配置特殊的异常类型.遇到某种异常回滚.
     *    属性2: noRollbackFor 可以配置异常类型 遇到某种异常不回滚.
     * @param id
     */
    @Override
    @Transactional //Spring默认提供的事务控制的注解
    public void deleteUserById(Integer id){
        userMapper.deleteById(id);
    }


    /**
     * 需求: 进行分页查询   总数 分页后的结果
     * 知识铺垫:  每页20条
     *      Sql: select * from user limit 起始位置,每页条数
     *      第一页:
     *          select * from user limit 0,20  下标[0-19]
     *      第二页:
     *          select * from user limit 20,20 下标[20-39]
     *      第三页:
     *          select * from user limit 40,20 下标[40-59]
     *      第N页:
     *          select * from user limit (n-1)*rows,rows
     * @param pageResult
     * @return
     *  方法实现:
     *          1.手写Sql
     *          2.利用MP方式实现
     */
    /*@Override
    public PageResult getUserList(PageResult pageResult) {
        //起始位置
        int start = (pageResult.getPageNum()-1) * pageResult.getPageSize();
        //每页条数
        int size = pageResult.getPageSize();
        //分页结果
        List<User> userList = userMapper.findUserListByPage(start,size);
        //是user表的总数信息 暂时不需要where条件.
        long total = userMapper.selectCount(null);
        //封装数据实现返回
        pageResult.setTotal(total).setRows(userList);
        return pageResult;
    }*/
}
